﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ubatic.Contracts.Services;
using Ubatic.Contracts.Contracts;
using Ubatic.Data;
using Web.Framework.Mapper;
using System.Transactions;
using Ubatic.Contracts.Enums;

namespace Ubatic.Services
{
    public class ConvocatoriaService : IConvocatoriaService
    {
        #region [Private Methods]
        
        private Proyecto ObtenerProyecto(UbaticEntities ctx, long proyectoId)
        {
            return ctx.Proyectoes.Where(p => p.Id == proyectoId).FirstOrDefault();
        }

        private string ObtenerCodigo(UbaticEntities ctx, Convocatoria convocatoria)
        {
            string codigoConvocatoria = convocatoria.TipoConvocatoria.Codigo;
            string numeroProyecto = string.Format("{0:00000}", convocatoria.NumeroProyecto);
            return codigoConvocatoria + numeroProyecto;
        }

        private Convocatoria ObtenerConvocatoria(UbaticEntities ctx, long convocatoriaId)
        {
            return ctx.Convocatoria.Where(c => c.Id == convocatoriaId).SingleOrDefault();
        }

        private ProyectoVersion ObtenerProyectoVersion(UbaticEntities ctx, long proyectoVersionId)
        {
            return ctx.ProyectoVersions.Where(pv => pv.Id == proyectoVersionId).SingleOrDefault();
        }

        private ProyectoDatoPrincipal ObtenerDatoPrincipal(UbaticEntities ctx, long proyectoVersionId)
        {
            ProyectoVersion proyectoVersion = this.ObtenerProyectoVersion(ctx, proyectoVersionId);
            return proyectoVersion.ProyectoDatoPrincipals.SingleOrDefault();
        }

        #endregion [Private Methods]

        public List<ConvocatoriaDto> ObtenerConvocatorias(ConvocatoriaCriteriaDto criteria)
        {
            using (var ctx = new UbaticEntities())
            {
                IQueryable<Convocatoria> query = ctx.Convocatoria;
                List<Convocatoria> convocatorias = query.OrderByDescending(c => c.PresentacionFin).ToList();
                return EntityMapper.ToDtoList<ConvocatoriaDto, Convocatoria>(convocatorias);
            }
        }

        public List<ProyectoDto> ObtenerProyectos(long convocatoriaId)
        {
            using (var ctx = new UbaticEntities())
            {
                IQueryable<Proyecto> query = ctx.Proyectoes;

                if (convocatoriaId > 0)
                {
                    query = query.Where(p => p.ConvocatoriaId == convocatoriaId);
                }

                return ToDtoList(query.ToList());
            }            
        }

        public long CrearProyectoVacio(long convocatoriaId, long usuarioId)
        {
            long proyectoId = 0;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (var ctx = new UbaticEntities())
                {
                    Proyecto proyecto = new Proyecto();

                    Convocatoria convocatoria = this.ObtenerConvocatoria(ctx, convocatoriaId);
                    if (convocatoria != null)
                    {
                        // Proyecto
                        proyecto.CodigoProyecto = this.ObtenerCodigo(ctx, convocatoria);
                        // sumo 1 la numero de Proyecto de la convocatoria
                        convocatoria.NumeroProyecto++;
                        proyecto.ConvocatoriaId = convocatoriaId;
                        proyecto.VersionActual = 1;
                        proyecto.EstadoProyectoId = (int)EstadoProyectoEnum.Abierto; // 1 = Abierto

                        // Proyecto Version
                        ProyectoVersion proyectoVersion = new ProyectoVersion();
                        proyectoVersion.Proyecto = proyecto;
                        proyectoVersion.Version = 1;

                        // Proyecto Dato Principal
                        ProyectoDatoPrincipal datoPrincipal = new ProyectoDatoPrincipal();
                        datoPrincipal.ProyectoVersion = proyectoVersion;
                        datoPrincipal.DirectorId = usuarioId;
                        
                        // Equipo
                        Equipo equipo = new Equipo();
                        equipo.ProyectoVersion = proyectoVersion;

                        // Integrante 
                        UserService usuarioSvc = new UserService();
                        Usuario usuario = usuarioSvc.ObtenerUsuario(ctx, usuarioId);
                        Integrante integrante = new Integrante();
                        integrante.Apellido = usuario.Apellido;
                        integrante.Nombre = usuario.Nombre;
                        integrante.Cuil = usuario.Cuil;
                        integrante.Email = usuario.CorreoElectronico;
                        integrante.DependenciaId = usuario.DependenciaId;
                        integrante.TipoDocumentoId = usuario.TipoDocumentoId;
                        integrante.NumeroDocumento = usuario.NroDocumento;

                        // Equipo Integrante
                        EquipoIntegrante equipoIntegrante = new EquipoIntegrante();
                        equipoIntegrante.Equipo = equipo;
                        equipoIntegrante.Integrante = integrante;
                        equipoIntegrante.VigenciaDesde = DateTime.Now;
                        equipoIntegrante.RoleIntegranteId = 1; // #TODO: Hacer Enum de Roles. ( 1 = Director )

                        ctx.SaveChanges();
                        tScope.Complete();

                        proyectoId = proyecto.Id;
                    }
                }
            }
            return proyectoId;
        }

        public ProyectoDto ObtenerProyecto(long proyectoId)
        {
            ProyectoDto proyectoDto = null;
            using (var ctx = new UbaticEntities())
            {
                Proyecto proyecto = this.ObtenerProyecto(ctx, proyectoId);
                if (proyecto != null)
                {
                    proyectoDto = new ProyectoDto();
                    ToProyectoDto(proyecto, proyectoDto);
                }
            }
            return proyectoDto;
        }

        #region [Dato Principal]

        public ProyectoDatoPrincipalDto ObtenerProyectoDatoPrincipal(long proyectoVersionId)
        {
            ProyectoDatoPrincipalDto dto = null;
            using(var ctx = new UbaticEntities())
            {
                ProyectoDatoPrincipal datoPrincipal = this.ObtenerDatoPrincipal(ctx, proyectoVersionId);
                if (datoPrincipal != null)
                {
                    dto = new ProyectoDatoPrincipalDto();
                    EntityMapper.Map(datoPrincipal, dto);
                    dto.ProyectoId = this.ObtenerProyectoVersion(ctx, proyectoVersionId).ProyectoId;
                }
            }
            
            return dto;
        }

        public void GuardarProyectoDatoPrincipal(ProyectoDatoPrincipalDto proyectoDatoPrincipalDto)
        {
            using (var ctx = new UbaticEntities())
            {
                ProyectoDatoPrincipal datoPrincipal = null;
                if (proyectoDatoPrincipalDto.Id == 0)
                {
                    datoPrincipal = new ProyectoDatoPrincipal();
                }
                else
                {
                    datoPrincipal = this.ObtenerDatoPrincipal(ctx, proyectoDatoPrincipalDto.ProyectoVersionId);
                }
                EntityMapper.Map(proyectoDatoPrincipalDto, datoPrincipal);
                ctx.SaveChanges();
            }                        
        }

        public void AgregarPalabraClave(PalabraClaveDto palabraClaveDto)
        {
            using (var ctx = new UbaticEntities())
            {
                PalabraClave palabraClave = new PalabraClave();
                EntityMapper.Map(palabraClaveDto, palabraClave);
                ProyectoVersion proyectoVersion = this.ObtenerProyectoVersion(ctx, palabraClaveDto.ProyectoVersionId);
                if (proyectoVersion != null)
                {
                    proyectoVersion.PalabraClaves.Add(palabraClave);
                }
                ctx.SaveChanges();
            }            
        }

        public void EliminarPalabraClave(long proyectoVersionId, long palabraClaveId)
        {
            using (var ctx = new UbaticEntities())
            {                
                ProyectoVersion proyectoVersion = this.ObtenerProyectoVersion(ctx, proyectoVersionId);
                PalabraClave palabraClave = proyectoVersion.PalabraClaves.Where(pc => pc.Id == palabraClaveId).Single();
                proyectoVersion.PalabraClaves.Remove(palabraClave);
                ctx.SaveChanges();
            }
        }

        public List<PalabraClaveDto> ObtenerPalabrasClave(long proyectoVersionId)
        {            
            using (var ctx = new UbaticEntities())
            {
                List<PalabraClave> palabrasClave = this.ObtenerProyectoVersion(ctx,proyectoVersionId).PalabraClaves.ToList();
                return EntityMapper.ToDtoList<PalabraClaveDto, PalabraClave>(palabrasClave);
            }            
        }

        public void AgregarAreaConocimiento(AreaConocimientoDto areaConocimientoDto)
        {
            using (var ctx = new UbaticEntities())
            {
                AreaConocimiento areaConocimiento = new AreaConocimiento();
                EntityMapper.Map(areaConocimientoDto, areaConocimiento);
                ProyectoVersion proyectoVersion = this.ObtenerProyectoVersion(ctx, areaConocimientoDto.ProyectoVersionId);
                if (proyectoVersion != null)
                {
                    proyectoVersion.AreaConocimientoes.Add(areaConocimiento);
                }
                ctx.SaveChanges();
            }
        }

        public List<AreaConocimientoDto> ObtenerAreaConocimientos(long proyectoVersionId)
        {
            using (var ctx = new UbaticEntities())
            {
                List<AreaConocimiento> areaConocimiento = this.ObtenerProyectoVersion(ctx, proyectoVersionId).AreaConocimientoes.ToList();
                return EntityMapper.ToDtoList<AreaConocimientoDto, AreaConocimiento>(areaConocimiento);
            }
        }

        public void EliminarAreaConocimiento(long proyectoVersionId, long areaConocimientoId)
        {
            using (var ctx = new UbaticEntities())
            {
                ProyectoVersion proyectoVersion = this.ObtenerProyectoVersion(ctx, proyectoVersionId);
                AreaConocimiento areaConocimiento = proyectoVersion.AreaConocimientoes.Where(pc => pc.Id == areaConocimientoId).Single();
                proyectoVersion.AreaConocimientoes.Remove(areaConocimiento);
                ctx.SaveChanges();
            }        
        }

        public void AgregarAsignatura(AsignaturaDto asignaturaDto)
        {
            using (var ctx = new UbaticEntities())
            {
                Asignatura asignatura = new Asignatura();
                EntityMapper.Map(asignaturaDto, asignatura);
                ProyectoVersion proyectoVersion = this.ObtenerProyectoVersion(ctx, asignaturaDto.ProyectoVersionId);
                if (proyectoVersion != null)
                {
                    proyectoVersion.Asignaturas.Add(asignatura);
                }
                ctx.SaveChanges();
            }
        }

        public List<AsignaturaDto> ObtenerAsignaturas(long proyectoVersionId)
        {
            using (var ctx = new UbaticEntities())
            {
                List<Asignatura> asignaturas = this.ObtenerProyectoVersion(ctx, proyectoVersionId).Asignaturas.ToList();
                return EntityMapper.ToDtoList<AsignaturaDto, Asignatura>(asignaturas);
            }
        }

        public void EliminarAsignatura(long proyectoVersionId, long asignaturaId)
        {
            using (var ctx = new UbaticEntities())
            {
                ProyectoVersion proyectoVersion = this.ObtenerProyectoVersion(ctx, proyectoVersionId);
                Asignatura asignatura = proyectoVersion.Asignaturas.Where(pc => pc.Id == asignaturaId).Single();
                proyectoVersion.Asignaturas.Remove(asignatura);
                ctx.SaveChanges();
            }
        }

        #endregion [Dato Principal]

        #region [Conversion]

        public static List<ProyectoDto> ToDtoList(List<Proyecto> proyectoList)
        {
            List<ProyectoDto> tDtoList = new List<ProyectoDto>();

            ProyectoDto dto = default(ProyectoDto);
            foreach (var proyecto in proyectoList)
            {
                dto = new ProyectoDto();
                ToProyectoDto(proyecto, dto);
                tDtoList.Add(dto);
            }

            return tDtoList;
        }

        private static void ToProyectoDto(Proyecto proyecto, ProyectoDto dto)
        {
            EntityMapper.Map(proyecto, dto);
            if(proyecto.EstadoProyecto != null)
            {
                dto.EstadoId = proyecto.EstadoProyecto.Id;                
                dto.EstadoDescripcion = proyecto.EstadoProyecto.Nombre;
            }            
            if (proyecto.ProyectoVersions.Count > 0)
            {
                ProyectoVersion proyectoVersion = proyecto.ProyectoVersions.OrderByDescending(pv => pv.Version).First();
                dto.ProyectoVersionId = proyectoVersion.Id;

                // Datos Principal
                ProyectoDatoPrincipal proyectoDatoPrincipal = proyectoVersion.ProyectoDatoPrincipals.FirstOrDefault();
                dto.ProyectoDatoPrincipalId = proyectoDatoPrincipal.Id;
                if (proyectoDatoPrincipal != null)
                {                     
                    dto.Titulo = proyectoVersion.ProyectoDatoPrincipals.First().Titulo;
                    // Datos?                   
                    if (proyectoDatoPrincipal.LineaTrabajoId.HasValue &&
                       !string.IsNullOrEmpty(proyectoDatoPrincipal.Resumen) &&
                       !string.IsNullOrEmpty(proyectoDatoPrincipal.Matricula) &&
                       proyectoDatoPrincipal.DependenciaId.HasValue &&
                       proyectoVersion.PalabraClaves.Count > 0 &&
                       proyectoVersion.Asignaturas.Count > 0 &&
                       proyectoVersion.AreaConocimientoes.Count > 0)
                    {
                        dto.DatoPrincipalConDatos = true;
                    }
                }
                // Director (#TODO)

                // Equipo de Trabajo
                Equipo equipo = proyectoVersion.Equipoes.FirstOrDefault();
                if (equipo != null &&
                    !string.IsNullOrEmpty(equipo.Experiencia) &&
                    !string.IsNullOrEmpty(equipo.EquipoRelacionado))
                {
                    dto.EquipoDeTrabajoConDatos = true;
                }

                // Tecnologia
                dto.TecnologiaConDatos = proyectoVersion.Tecnologias.Count > 0;

                // Actores, Seguimiento y Evaluacion
                dto.ActoresSeguimientoEvaluacionConDatos = proyectoVersion.ActoresSeguimientoEvaluacions.Count > 0;

                // Presupuesto
                Convocatoria convocatoria = proyecto.Convocatoria;

                int cantAnios = (int) Math.Ceiling((convocatoria.VigenciaHasta.Value - convocatoria.VigenciaDesde.Value).Days / (decimal)366);
                int anioDesde = convocatoria.VigenciaDesde.Value.Year;
                int anioHasta = convocatoria.VigenciaDesde.Value.Year + cantAnios;
                dto.PresupuestoConDatos = true;
                for(int i = anioDesde; i<=anioHasta; i++)
                {
                    Recurso recursoPorAnio = proyectoVersion.Recursoes.Where(r => r.Anio == anioDesde).FirstOrDefault();
                    if (recursoPorAnio == null)
                    {
                        dto.PresupuestoConDatos = false;
                        break;
                    }
                }

                // Cronograma de etapas
                dto.CronogramaDeEtapasConDatos = proyectoVersion.Etapas.Count > 0;

                // Cronograma de actividades
                if(proyectoVersion.Actividads.Count > 0)
                {
                    foreach (var etapa in proyectoVersion.Etapas)
                    {
                        if (etapa.Actividads.Count == 0)
                        {
                            dto.CronogramaDeActividadesConDatos = false;
                            break;
                        }
                    }
                }
             
                //Bibliografia
                dto.Bibliografia = proyectoVersion.Bibliografias.Count > 0;
            }
        }

        #endregion [Conversion]
    }
}
